package common

import "fmt"

type LockArguments struct {
	Client_portID int
	Request_time  string
	Notebook      map[string]bool
}

const (
	TimeFormat = "15:04:55"
)

type LockState struct {
	Occupier_portID int
	Occupied_time   string
	Notebook        map[string]bool
}

var sharedLock LockState
var Unittest_count int = 0
var simulateLock chan bool = make(chan bool, 1)

type LockService struct{}

func (s *LockService) Acquire(args *LockArguments, result *LockState) error {
	if args == nil {
		return fmt.Errorf("port ID & time cannot be empty: %v", args)
	}

	if result == nil {
		return fmt.Errorf("Result memory is unset")
	}

	// at most once去重
	if args.Notebook == nil {
		(*args).Notebook = make(map[string]bool)
	}
	defer func() {
		(*result).Notebook = args.Notebook
	}()
	{
		key := fmt.Sprintf("%d+%s", args.Client_portID, args.Request_time)
		_, exists := args.Notebook[key]
		if exists {
			return fmt.Errorf("re-post of request is denied: port ID %d; time %s",
				args.Client_portID, args.Request_time)
		}
		(*args).Notebook[key] = true
	}

	simulateLock <- true
	// 检验锁正确性
	Unittest_count++
	defer func() {
		<-simulateLock
	}()

	// 锁未被占用, 可上锁
	if sharedLock.Occupier_portID <= 0 {
		sharedLock.Occupier_portID = args.Client_portID
		sharedLock.Occupied_time = args.Request_time
		(*result).Occupied_time = args.Request_time
		(*result).Occupier_portID = args.Client_portID
		return nil
	}

	// 锁已被占用, 不可占用
	(*result).Occupied_time = ""
	(*result).Occupier_portID = 0
	return fmt.Errorf("lock has been by occupied by %d at %s",
		sharedLock.Occupier_portID, sharedLock.Occupied_time)
}

func (s *LockService) Query(_ *LockArguments, result *LockState) error {
	simulateLock <- true
	defer func() {
		<-simulateLock
	}()

	if result == nil {
		return fmt.Errorf("result memory is unset")
	}

	*result = sharedLock
	return nil
}

func (s *LockService) Release(args *LockArguments, result *LockState) error {
	if args == nil {
		return fmt.Errorf("portID & time cannot be empty: %v", args)
	}

	if result == nil {
		return fmt.Errorf("result memory is unset")
	}

	// at most once去重
	// at most once去重
	if args.Notebook == nil {
		(*args).Notebook = make(map[string]bool)
	}
	defer func() {
		(*result).Notebook = args.Notebook
	}()
	{
		key := fmt.Sprintf("%d+%s", args.Client_portID, args.Request_time)
		_, exists := args.Notebook[key]
		if exists {
			return fmt.Errorf("re-post of request is denied: port ID %d; time %s",
				args.Client_portID, args.Request_time)
		}
		(*args).Notebook[key] = true
	}

	simulateLock <- true
	Unittest_count++
	defer func() {
		<-simulateLock
	}()

	// 锁原本未上锁, 不可解锁
	if sharedLock.Occupier_portID <= 0 {
		// haven't been occupied
		return fmt.Errorf("lock can't be re-freed")
	}
	if sharedLock.Occupier_portID != args.Client_portID {
		// diff ID
		(*result).Occupied_time = sharedLock.Occupied_time
		(*result).Occupier_portID = sharedLock.Occupier_portID
		return fmt.Errorf("lock was in use of other client: %d", sharedLock.Occupier_portID)
	}

	// 锁已占用且身份对应
	sharedLock.Occupied_time = ""
	sharedLock.Occupier_portID = 0
	return nil
}
